import configparser
import importlib.resources as resources_lib
import json
import os
from contextlib import AbstractContextManager
from pathlib import Path
from typing import IO, Any, Dict, Optional, TypeVar, Union

from interview_voice_project.common import get_logger

# 可选导入yaml，如项目需要可添加到依赖中
try:
    import yaml

    HAS_YAML = True
except ImportError:
    HAS_YAML = False

from interview_voice_project import resources  # 导入资源包

logger = get_logger(__name__)


class ResourceLoader:
    """资源文件加载工具类，统一读取 resources 包下的资源"""

    @staticmethod
    def read_text(resource_path: str, encoding: str = "utf-8") -> str:
        """
        读取文本资源（如 .txt, .ini, .json 等）
        :param resource_path: 资源相对于 resources 包的路径（如 "config.ini"、"prompts/science_prompt.txt"）
        """
        try:
            return resources_lib.read_text(resources, resource_path, encoding=encoding)
        except FileNotFoundError as e:
            logger.error(f"文本资源不存在：{resource_path}，错误：{e}")
            raise
        except Exception as e:
            logger.error(f"读取文本资源失败：{resource_path}，错误：{e}")
            raise

    @staticmethod
    def read_binary(resource_path: str) -> bytes:
        """读取二进制资源（如 .png, .zip 等）"""
        try:
            return resources_lib.read_binary(resources, resource_path)
        except FileNotFoundError as e:
            logger.error(f"二进制资源不存在：{resource_path}，错误：{e}")
            raise
        except Exception as e:
            logger.error(f"读取二进制资源失败：{resource_path}，错误：{e}")
            raise

    @staticmethod
    def get_path(resource_path: str) -> AbstractContextManager[Path]:
        """
        获取资源文件的路径（适合需要路径操作的场景，如 pandas 读 CSV）
        注意：with 语句内使用，确保资源句柄正确释放
        """
        try:
            # 返回 pathlib.Path 对象，支持上下文管理器（自动释放资源）
            return resources_lib.path(resources, resource_path)
        except FileNotFoundError as e:
            logger.error(f"资源路径不存在：{resource_path}，错误：{e}")
            raise e
        except Exception as e:
            logger.error(f"获取资源路径失败：{resource_path}，错误：{e}")
            raise e


class ConfigParser:
    """配置文件解析器，支持不同格式配置文件的读取和解析"""

    @staticmethod
    def parse_ini(config_content: str) -> Dict[str, Dict[str, str]]:
        """解析INI格式配置"""
        parser = configparser.ConfigParser()
        parser.read_string(config_content)

        result = {}
        for section in parser.sections():
            result[section] = dict(parser[section])
        return result

    @staticmethod
    def parse_json(config_content: str) -> Dict[str, Any]:
        """解析JSON格式配置"""
        return json.loads(config_content)

    @staticmethod
    def parse_yaml(config_content: str) -> Dict[str, Any]:
        """解析YAML格式配置"""
        if not HAS_YAML:
            raise ImportError("解析YAML需要安装PyYAML，请执行：pip install pyyaml")
        try:
            return yaml.safe_load(config_content)
        except yaml.YAMLError as e:
            logger.error(f"解析YAML配置失败：{e}")
            raise e

    @classmethod
    def parse(cls, config_content: str, file_type: str) -> Dict[str, Any]:
        """
        根据文件类型解析配置内容
        :param config_content: 配置文件内容
        :param file_type: 文件类型，如 'ini', 'json', 'yaml'
        :return: 解析后的配置字典
        """
        file_type = file_type.lower()

        if file_type == 'ini':
            return cls.parse_ini(config_content)
        elif file_type == 'json':
            return cls.parse_json(config_content)
        elif file_type in ('yaml', 'yml'):
            return cls.parse_yaml(config_content)
        else:
            raise ValueError(f"不支持的文件类型：{file_type}")


class ConfigObject:
    """配置对象，支持通过属性访问配置项"""

    def __init__(self, config_dict: Dict[str, Any]):
        self._config = config_dict
        self._init_attrs(config_dict)

    def _init_attrs(self, config_dict: Dict[str, Any]):
        """初始化配置属性"""
        for key, value in config_dict.items():
            # 转换键名为大写，使用下划线分隔
            attr_name = key.upper().replace('.', '_')

            if isinstance(value, dict):
                # 递归创建嵌套的配置对象
                setattr(self, attr_name, ConfigObject(value))
            elif isinstance(value, str) and value.startswith('[') and value.endswith(']'):
                # 尝试解析字符串列表
                try:
                    parsed_value = json.loads(value)
                    setattr(self, attr_name, parsed_value)
                except json.JSONDecodeError:
                    setattr(self, attr_name, value)
            else:
                # 基本类型直接设置
                setattr(self, attr_name, value)

    def __getattr__(self, name: str) -> Any:
        """获取不存在的属性时返回None"""
        logger.warning(f"配置项 {name} 不存在")
        return None

    def get(self, name: str, default: Any = None) -> Any:
        """获取配置项，支持点号分隔的嵌套路径"""
        if '.' not in name:
            return getattr(self, name, default)

        parts = name.split('.')
        current = self
        for part in parts:
            if not hasattr(current, part):
                return default
            current = getattr(current, part)
        return current

    def to_dict(self) -> Dict[str, Any]:
        """将配置对象转换为字典"""
        return self._config


class ConfigLoader:
    """配置加载器，负责从资源加载配置并解析"""

    def __init__(self):
        self._config_cache = {}

    def load_config(self, resource_path: str, file_type: Optional[str] = None) -> ConfigObject:
        """
        加载并解析配置文件
        :param resource_path: 资源路径
        :param file_type: 文件类型，如果为None则从文件名推断
        :return: 配置对象
        """
        # 检查缓存
        if resource_path in self._config_cache:
            return self._config_cache[resource_path]

        # 推断文件类型
        if file_type is None:
            _, ext = os.path.splitext(resource_path)
            file_type = ext.lstrip('.').lower() if ext else 'ini'

        # 读取并解析配置
        config_content = ResourceLoader.read_text(resource_path)
        config_dict = ConfigParser.parse(config_content, file_type)
        config_obj = ConfigObject(config_dict)

        # 缓存配置对象
        self._config_cache[resource_path] = config_obj

        return config_obj

resource_loader = ResourceLoader()
# 实例化全局对象，方便外部直接调用
config_loader = ConfigLoader()
config_ini = config_loader.load_config("config.ini")

if __name__ == '__main__':
    # 测试配置访问
    print(f"MySQL主机: {config_ini.MYSQL.HOST}")
    print(f"语音模型路径: {config_ini.VOICE_MODEL.SVS_MODEL_PATH}")
    print(f"LLM模型: {config_ini.LLM.DEEPSEEK_MODEL}")

    # 使用get方法访问嵌套配置
    print(f"使用get方法访问MySQL主机: {config_ini.get('MYSQL.HOST')}")

